package com.weishi.project.training.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weishi.common.utils.DateUtils;
import com.weishi.project.speedometer.vo.PropellerFrequencyData;
import com.weishi.project.speedometer.vo.PropellerFrequencyWitVo;
import com.weishi.project.training.domain.WitAccLog;
import com.weishi.project.training.mapper.WitAccLogMapper;
import com.weishi.project.training.service.IWitAccLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

@Service
public class WitAccLogServiceImpl extends ServiceImpl<WitAccLogMapper, WitAccLog> implements IWitAccLogService {

    @Autowired
    Environment environment;

    @Autowired
    private WitAccLogMapper witAccLogMapper;

    Logger logger = Logger.getLogger("AccelerationLogServiceImpl");

    List<WitAccLog> selectAccelerationLogList(WitAccLog accelerationLog) {
        return witAccLogMapper.selectWitAccLogList(accelerationLog);
    }

    @Override
    public int qryCurrentPropellerFrequency(List<WitAccLog> witAccLogs) {
        int count = 4;
        int propellerFrequency = 0;
        List<PropellerFrequencyData> list = getPropellerFrequencyData(witAccLogs, count, 0);
        if (list != null && list.size() > 1) {
            PropellerFrequencyData data = list.get(list.size() - 2);
            propellerFrequency = (int) data.getAveragePropeller();

            /*if (list.size() > count) {
                Double propellerFrequencyTotal = 0.0;
                for(int i = list.size()-2; i>=list.size() - count; i--){
                    propellerFrequencyTotal += (int) list.get(i).getAveragePropeller();
                }
                propellerFrequency = (int)(propellerFrequencyTotal/count-1);
            }*/
        } else if (list != null && list.size() == 1) {
            PropellerFrequencyData data = list.get(list.size() - 1);
            propellerFrequency = (int) data.getAveragePropeller();
        }
        return propellerFrequency;
    }

    @Override
    public List<PropellerFrequencyData> qryPropellerFrequencyDate(String devId, Integer channelId, long fristTime) {
        WitAccLog params = new WitAccLog();
//        if(StringUtils.isNotEmpty(devId))params.setDevId(devId);
        params.setChannelId(channelId);
        List<WitAccLog> accelerationLogs = witAccLogMapper.selectWitAccLogList(params);
        if(accelerationLogs==null && accelerationLogs.size()==0) return null;
        return getPropellerFrequencyData(accelerationLogs, 4, fristTime);
    }

    /**
     * @param dataVos
     * @param count     一次桨频算一次平均桨频
     * @param fristTime 开始时间
     * @return
     */
    private List<PropellerFrequencyData> getPropellerFrequencyData(List<WitAccLog> dataVos, int count, long fristTime) {
        String boatType = environment.getProperty("system.version");

        //测试环境的艇种根据登陆账号区分
        if(boatType.equals("demo") && dataVos!=null && dataVos.size()>0){
            String devId = dataVos.get(0).getDevId();
            boatType = devId.contains("HT") ? "h" : devId.contains("PT") ? "p" : "s";
        }
        List<PropellerFrequencyWitVo> list;
        if(boatType.equals("h")){
            list = getImportantPointH(dataVos);
        }else if(boatType.equals("p")){
            list = getImportantPointP(dataVos);
        }else{
            list = getImportantPointS(dataVos);
        }

        List<PropellerFrequencyData> ret = new ArrayList<>();
        if (list.size() < 3) {
            return ret;
        }

        for (int i = 0; i < list.size(); i++) {
            PropellerFrequencyData data = new PropellerFrequencyData();
            data.setCount(count);
            if (list.get(i).getType() == -1) {
                data.setStartTime(list.get(i).getRealTime());
                data.setStartTimeTimp(list.get(i).getTimeTimp());
                data.setRealTime(DateUtils.getStringTime(list.get(i).getTimeTimp() - fristTime));
                if ((i + count * 2) < list.size()) {
                    data.setDistanceTotal(list.get(i + count * 2).getDistanceTotal());
                    data.setDistance(list.get(i + count * 2).getDistanceTotal() - list.get(i).getDistanceTotal());
                    data.setEndTime(list.get(i + count * 2).getRealTime());
                    data.setEndTimeTimp(list.get(i + count * 2).getTimeTimp());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 1000.0;
                    double averagePropeller = count / (minute / 60.0);
                    if (boatType.equals("p")) averagePropeller = averagePropeller * 2;
                    data.setAveragePropeller(averagePropeller);
                } else {
                    PropellerFrequencyWitVo temp = list.get(list.size() - 1).getType() == -1 ? list.get(list.size() - 1) : list.get(list.size() - 2);
                    int countTemp = list.get(list.size() - 1).getType() == -1 ? (list.size() - 1 - i) / 2 : (list.size() - 2 - i) / 2;
                    data.setEndTime(temp.getRealTime());
                    data.setEndTimeTimp(temp.getTimeTimp());
                    data.setDistanceTotal(temp.getDistanceTotal());
                    data.setDistance(temp.getDistanceTotal() - list.get(i).getDistanceTotal());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 60000.0;
                    double averagePropeller = minute != 0 ? countTemp / minute : 0.0;
                    if (boatType.equals("p")) averagePropeller = averagePropeller * 2;
                    data.setAveragePropeller(averagePropeller);
                }

                ret.add(data);
            }
        }
        return ret;
    }

    @Override
    public List<WitAccLog> qryWitAccLogList(Integer channelId) {
        WitAccLog params = new WitAccLog();
        params.setChannelId(channelId);
        return witAccLogMapper.selectWitAccLogList(params);
    }

    public List<PropellerFrequencyData> getPropellerFrequencyData(List<WitAccLog> dataVos, int count) {
        String boatType = environment.getProperty("system.version");
        //测试环境的艇种根据登陆账号区分
        if(boatType.equals("demo") && dataVos!=null && dataVos.size()>0){
            String devId = dataVos.get(0).getDevId();
            boatType = devId.contains("HT") ? "h" : devId.contains("PT") ? "p" : "s";
        }
        List<PropellerFrequencyWitVo> list;
        if(boatType.equals("h")){
            list = getImportantPointH(dataVos);
        }else if(boatType.equals("p")){
            list = getImportantPointP(dataVos);
        }else{
            list = getImportantPointS(dataVos);
        }
        List<PropellerFrequencyData> ret = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            PropellerFrequencyData data = new PropellerFrequencyData();
            data.setCount(count);
            if (list.get(i).getType() == -1) {
                data.setStartTime(list.get(i).getRealTime());
                data.setStartTimeTimp(list.get(i).getTimeTimp());

                if ((i + count * 2) < list.size()) {
                    data.setDistanceTotal(list.get(i + count * 2).getDistanceTotal());
                    data.setDistance(list.get(i + count * 2).getDistanceTotal() - list.get(i).getDistanceTotal());
                    data.setEndTime(list.get(i + count * 2).getRealTime());
                    data.setEndTimeTimp(list.get(i + count * 2).getTimeTimp());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 1000.0;
                    double averagePropeller = count / (minute / 60.0);
                    if (averagePropeller > 150) {
                        averagePropeller = 140;
                    }
                    if (boatType.equals("p")) averagePropeller = averagePropeller * 2;
                    data.setAveragePropeller(averagePropeller);
                } else {
                    PropellerFrequencyWitVo temp = (i + count * 2) <= list.size() ? list.get(i + count) : list.get(i);
                    data.setEndTime(temp.getRealTime());
                    data.setEndTimeTimp(temp.getTimeTimp());
                    data.setDistanceTotal(temp.getDistanceTotal());
                    data.setDistance(temp.getDistanceTotal() - list.get(i).getDistanceTotal());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 60000.0;
                    double averagePropeller = minute != 0 ? 1 / minute : 0.0;
                    if (averagePropeller > 150) {
                        averagePropeller = 140;
                    }
                    if (boatType.equals("p")) averagePropeller = averagePropeller * 2;
                    data.setAveragePropeller(averagePropeller);
                }
                data.setRealTime(data.getEndTime());

                ret.add(data);
            }
        }
        return ret;
    }

    /**
     * 获取波峰波谷
     *
     * @param dataVos
     * @return
     */
    private List<PropellerFrequencyWitVo> getImportantPointH(List<WitAccLog> dataVos) {
        List<PropellerFrequencyWitVo> dataVoList = null;
        try {
            dataVoList = new ArrayList<>();
            List<Double> distances = new ArrayList<>();
            for (WitAccLog gpsVo : dataVos) {
                distances.add(gpsVo.getAngley());
            }
            double[] data = new double[dataVos.size()];
            int index = 0;
            for (Double aa : distances) {
                data[index++] = aa;
            }
            int peak = 0;

            try {
                int[] PeakAndTrough = new int[data.length];

                //需要三个不同的值进行比较，取lo,mid，hi分别为三值
                for (int lo = 0, mid = 1, hi = 2; hi < data.length; hi++) {
                    //先令data[lo]不等于data[mid]
                    while (mid < data.length && data[mid] == data[lo]) {
                        mid++;
                    }

                    hi = mid + 1;

                    //令data[hi]不等于data[mid]
                    while (hi < data.length && data[hi] == data[mid]) {
                        hi++;
                    }

                    if (hi >= data.length) {
                        break;
                    }

                    //检测是否为峰值
                    if (data[mid] > data[lo] && data[mid] > data[hi]) {
                        PeakAndTrough[mid] = 1;       //1代表波峰
                    } else if (data[mid] < data[lo] && data[mid] < data[hi]) {
                        PeakAndTrough[mid] = -1;      //-1代表波谷
                    }

                    lo = mid;
                    mid = hi;
                }

                //计算均值
                float ave = 0;
                for (int i = 0; i < data.length; i++) {
                    ave += data[i];
                }
                ave /= data.length;


                //排除大于均值的波谷和小于均值的波峰
                /*for (int i = 0; i < PeakAndTrough.length; i++) {
                    if ((PeakAndTrough[i] > 0 && data[i] < ave) || (PeakAndTrough[i] < 0 && data[i] > ave)) {
                        PeakAndTrough[i] = 0;
                    }
                }*/

                //统计波谷数量
                for (int i = 0; i < PeakAndTrough.length; i++) {
                    if (PeakAndTrough[i] != 0) {
                        PropellerFrequencyWitVo vo = new PropellerFrequencyWitVo();
                        vo.setType(PeakAndTrough[i]);
                        vo.setRealTime(dataVos.get(i).getTimp());
                        vo.setTimeTimp(Long.parseLong(dataVos.get(i).getTimp()));
                        vo.setWitAccLog(dataVos.get(i));
                        dataVoList.add(vo);

                        dataVos.get(i).setNode(PeakAndTrough[i]);
                    }
                }

                //旋转角度大于40度为有效桨 划艇：80-300
                double minEffectiveValue = 20;
                double maxEffectiveValue = 100;
                List<PropellerFrequencyWitVo> remove = new ArrayList<>();
                PropellerFrequencyWitVo pre = null;
                for (PropellerFrequencyWitVo vo : dataVoList) {
                    if (pre == null) {
                        pre = vo;
                        continue;
                    }
                    WitAccLog witAccLog = vo.getWitAccLog();
                    if ((pre.getWitAccLog().getAngley() - witAccLog.getAngley() > minEffectiveValue || witAccLog.getAngley() - pre.getWitAccLog().getAngley() > minEffectiveValue) && (pre.getWitAccLog().getAngley() - witAccLog.getAngley() < maxEffectiveValue || witAccLog.getAngley() - pre.getWitAccLog().getAngley() < maxEffectiveValue)) {
                        pre = vo;
                    } else {
                        vo.setType(0);
                        witAccLog.setNode(0);
                        remove.add(vo);
                    }
                }
                //去除因角度旋转不够删除的波峰波谷
                dataVoList.removeAll(remove);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataVoList;
    }

    private List<PropellerFrequencyWitVo> getImportantPointP(List<WitAccLog> dataVos) {
        List<PropellerFrequencyWitVo> dataVoList = null;
        try {
            dataVoList = new ArrayList<>();

            List<Double> distances = new ArrayList<>();
            for (WitAccLog gpsVo : dataVos) {
                distances.add(gpsVo.getAngley());
            }
            double[] data = new double[dataVos.size()];
            int index = 0;
            for (Double aa : distances) {
                data[index++] = aa;
            }
            int peak = 0;

            try {
                int[] PeakAndTrough = new int[data.length];

                //需要三个不同的值进行比较，取lo,mid，hi分别为三值
                for (int lo = 0, mid = 1, hi = 2; hi < data.length; hi++) {
                    //先令data[lo]不等于data[mid]
                    while (mid < data.length && data[mid] == data[lo]) {
                        mid++;
                    }

                    hi = mid + 1;

                    //令data[hi]不等于data[mid]
                    while (hi < data.length && data[hi] == data[mid]) {
                        hi++;
                    }

                    if (hi >= data.length) {
                        break;
                    }

                    //检测是否为峰值
                    if (data[mid] > data[lo] && data[mid] > data[hi]) {
                        PeakAndTrough[mid] = 1;       //1代表波峰
                    } else if (data[mid] < data[lo] && data[mid] < data[hi]) {
                        PeakAndTrough[mid] = -1;      //-1代表波谷
                    }

                    lo = mid;
                    mid = hi;
                }

                //统计波谷数量
                for (int i = 0; i < PeakAndTrough.length; i++) {
                    if (PeakAndTrough[i] != 0) {
                        PropellerFrequencyWitVo vo = new PropellerFrequencyWitVo();
                        vo.setType(PeakAndTrough[i]);
                        vo.setRealTime(dataVos.get(i).getTimp());
                        vo.setTimeTimp(Long.parseLong(dataVos.get(i).getTimp()));
                        vo.setWitAccLog(dataVos.get(i));
                        dataVoList.add(vo);

                        dataVos.get(i).setNode(PeakAndTrough[i]);
                    }
                }

                //旋转角度大于40度为有效桨 皮艇：60
                double minEffectiveValue = 40;
                double maxEffectiveValue = 180;
                List<PropellerFrequencyWitVo> remove = new ArrayList<>();
                PropellerFrequencyWitVo pre = null;
                for (PropellerFrequencyWitVo vo : dataVoList) {
                    if (pre == null) {
                        pre = vo;
                        continue;
                    }
                    WitAccLog witAccLog = vo.getWitAccLog();
                        if ((pre.getWitAccLog().getAngley() - witAccLog.getAngley() > minEffectiveValue || witAccLog.getAngley() - pre.getWitAccLog().getAngley() > minEffectiveValue) && (pre.getWitAccLog().getAngley() - witAccLog.getAngley() < maxEffectiveValue || witAccLog.getAngley() - pre.getWitAccLog().getAngley() < maxEffectiveValue)) {
                        pre = vo;
                    } else {
                        vo.setType(0);
                        witAccLog.setNode(0);
                        remove.add(vo);
                    }
                }
                //去除因角度旋转不够删除的波峰波谷
                dataVoList.removeAll(remove);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataVoList;
    }

    private List<PropellerFrequencyWitVo> getImportantPointS(List<WitAccLog> dataVos) {
        List<PropellerFrequencyWitVo> dataVoList = null;
        try {
            dataVoList = new ArrayList<>();

            List<Double> distances = new ArrayList<>();
            for (WitAccLog gpsVo : dataVos) {
                distances.add(gpsVo.getAnglex());
            }
            double[] data = new double[dataVos.size()];
            int index = 0;
            for (Double aa : distances) {
                data[index++] = aa;
            }
            int peak = 0;

            try {
                int[] PeakAndTrough = new int[data.length];

                //需要三个不同的值进行比较，取lo,mid，hi分别为三值
                for (int lo = 0, mid = 1, hi = 2; hi < data.length; hi++) {
                    //先令data[lo]不等于data[mid]
                    while (mid < data.length && data[mid] == data[lo]) {
                        mid++;
                    }

                    hi = mid + 1;

                    //令data[hi]不等于data[mid]
                    while (hi < data.length && data[hi] == data[mid]) {
                        hi++;
                    }

                    if (hi >= data.length) {
                        break;
                    }

                    //检测是否为峰值
                    if (data[mid] > data[lo] && data[mid] > data[hi]) {
                        PeakAndTrough[mid] = 1;       //1代表波峰
                    } else if (data[mid] < data[lo] && data[mid] < data[hi]) {
                        PeakAndTrough[mid] = -1;      //-1代表波谷
                    }

                    lo = mid;
                    mid = hi;
                }

                //统计波谷数量
                for (int i = 0; i < PeakAndTrough.length; i++) {
                    if (PeakAndTrough[i] != 0) {
                        PropellerFrequencyWitVo vo = new PropellerFrequencyWitVo();
                        vo.setType(PeakAndTrough[i]);
                        vo.setRealTime(dataVos.get(i).getTimp());
                        vo.setTimeTimp(Long.parseLong(dataVos.get(i).getTimp()));
                        vo.setWitAccLog(dataVos.get(i));
                        dataVoList.add(vo);

                        dataVos.get(i).setNode(PeakAndTrough[i]);
                    }
                }

                //旋转角度大于40度为有效桨 赛艇：10-50
                double minEffectiveValue = 50;
                double maxEffectiveValue = 150;
                List<PropellerFrequencyWitVo> remove = new ArrayList<>();
                PropellerFrequencyWitVo pre = null;
                for (PropellerFrequencyWitVo vo : dataVoList) {
                    if (pre == null) {
                        pre = vo;
                        continue;
                    }
                    WitAccLog witAccLog = vo.getWitAccLog();
                    if ((pre.getWitAccLog().getAnglex() - witAccLog.getAnglex() > minEffectiveValue || witAccLog.getAnglex() - pre.getWitAccLog().getAnglex() > minEffectiveValue) && (pre.getWitAccLog().getAnglex() - witAccLog.getAnglex() < maxEffectiveValue || witAccLog.getAnglex() - pre.getWitAccLog().getAnglex() < maxEffectiveValue)) {
                        pre = vo;
                    } else {
                        vo.setType(0);
                        witAccLog.setNode(0);
                        remove.add(vo);
                    }
                }
                //去除因角度旋转不够删除的波峰波谷
                dataVoList.removeAll(remove);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataVoList;
    }

}
